home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Newswatcher 2.0b22 / NW Source / Source / datetime.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-19  |  7.3 KB  |  349 lines  |  [TEXT/MMCC]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     datetime.c
  4.  
  5.     This module converts RFC822 date/time lines into Mac-format date/time
  6.     strings in local time.
  7.     
  8.     Copyright © 1994, Northwestern University.
  9.  
  10. ----------------------------------------------------------------------------*/
  11.  
  12. #include <Script.h>
  13. #include <Packages.h>
  14.  
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <stdio.h>
  18. #include <ctype.h>
  19.  
  20. #include "glob.h"
  21. #include "datetime.h"
  22. #include "strutil.h"
  23.  
  24.  
  25.  
  26. /*----------------------------------------------------------------------------
  27.     Skip
  28.     
  29.     Skip white space and comments.
  30.     
  31.     Entry:    *str = string.
  32.     
  33.     Exit:    *str = pointer to first character following skipped white space
  34.                 and comments.
  35. ----------------------------------------------------------------------------*/
  36.  
  37. static void Skip (char **str)
  38. {
  39.     char *s;
  40.     short parenLevel;
  41.     
  42.     s = *str;
  43.     while (true) {
  44.         while (isLWSP(*s)) s++;
  45.         if (*s == '(') {
  46.             parenLevel = 1;
  47.             s++;
  48.             while (*s != 0 && parenLevel > 0) {
  49.                 if (*s == '(') {
  50.                     parenLevel++;
  51.                 } else if (*s == ')') {
  52.                     parenLevel--;
  53.                 }
  54.                 s++;
  55.             }
  56.         } else {
  57.             break;
  58.         }
  59.     }
  60.     *str = s;
  61. }
  62.  
  63.  
  64.  
  65. /*----------------------------------------------------------------------------
  66.     ParseNum
  67.     
  68.     Extract a long integer from a string.
  69.     
  70.     Entry:    *str = string.
  71.             min = minimum number of digits.
  72.             max = maximum number of digits.
  73.     
  74.     Exit:    function result = true if number parsed, false if syntax error.
  75.             *num = the number
  76.             *str = pointer to first character following parsed number.
  77. ----------------------------------------------------------------------------*/
  78.  
  79. static Boolean ParseNum (char **str, short min, short max, short *num)
  80. {
  81.     short n, numDigits;
  82.     char *p;
  83.     
  84.     p = *str;
  85.     if (!isdigit(*p)) return false;
  86.     n = CrackNum(&p);
  87.     numDigits = p - *str;
  88.     if (numDigits < min || numDigits > max) return false;
  89.     *str = p;
  90.     *num = n;
  91.     return true;
  92. }
  93.  
  94.  
  95.  
  96. /*----------------------------------------------------------------------------
  97.     FindDayOfWeek
  98.  
  99.     Given a string that might be a day of week abbreviation, return the number
  100.     of the day of the week (starting with Monday = 1, ...).
  101.     
  102.     Entry:    str = day of week string.
  103.     
  104.     Exit:    function result = day of week ordinal, or 0 if can't parse.
  105. ----------------------------------------------------------------------------*/
  106.  
  107. static short FindDayOfWeek (char *str)
  108. {
  109.     static char *days[7] = {
  110.         "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"
  111.     };
  112.     short i;
  113.     
  114.     for (i = 0; i < 7; i++) {
  115.         if (MyStrNEqual(str, days[i], 3)) return i+1;
  116.     }
  117.     return 0;
  118. }
  119.  
  120.  
  121.  
  122. /*----------------------------------------------------------------------------
  123.     FindMonth
  124.  
  125.     Given a string that might be a month abbreviation, return the number
  126.     of the month (starting with January = 1, ...).
  127.     
  128.     Entry:    str = month string.
  129.     
  130.     Exit:    function result = month ordinal, or 0 if can't parse.
  131. ----------------------------------------------------------------------------*/
  132.  
  133. static short FindMonth (char *str)
  134. {
  135.     static char *months[12] = {
  136.         "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
  137.         "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
  138.     };
  139.     short i;
  140.     
  141.     for (i = 0; i < 12; i++) {
  142.         if (MyStrNEqual(str, months[i], 3)) return i+1;
  143.     }
  144.     return 0;
  145. }
  146.  
  147.  
  148.  
  149. /*----------------------------------------------------------------------------
  150.     Parse822Date
  151.  
  152.     Parse a date/time that's in RFC822/1123 header format:
  153.     
  154.     Entry:    date = RFC822/1123 date/time string.
  155.     
  156.     Exit:    function result = number of seconds since January 1, 1904, 
  157.                 the standard Mac date convention.
  158.             function result = 0 if the date could not be parsed.
  159.             
  160.     date-time = [ day "," ] date time
  161.     
  162.     day = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
  163.     
  164.     date = 1*2DIGIT month 2*4DIGIT
  165.     
  166.     month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
  167.             "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
  168.             
  169.     time = hour zone
  170.     
  171.     hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT]
  172.     
  173.     zone = "UT" / "GMT" / "EST" / "EDT" / "CST" / "CDT" /
  174.            "MST" / "MDT" / "PST" / "PDT" / ( ("+" / "-") 4DIGIT
  175. ----------------------------------------------------------------------------*/
  176.  
  177. unsigned long Parse822Date (char *date)
  178. {
  179.     DateTimeRec dt;
  180.     unsigned long result;
  181.     char *p;
  182.     short sign = 1;
  183.     short tzDelta = 0;
  184.  
  185.     memset(&dt, 0, sizeof(dt));
  186.  
  187.     p = date;
  188.     
  189.     /* Day of week and comma. */
  190.  
  191.     Skip(&p);
  192.     if (isalpha(*p)) {
  193.         if (FindDayOfWeek(p) == 0) return 0;
  194.         p+= 3;
  195.         Skip(&p);
  196.         if (*p != ',') return 0;
  197.         p++;
  198.     }
  199.     
  200.     /* Date. */
  201.  
  202.     Skip(&p);
  203.     if (!ParseNum(&p, 1, 2, &dt.day)) return 0;
  204.  
  205.     Skip(&p);
  206.     dt.month = FindMonth(p);
  207.     if (dt.month == 0) return 0;
  208.     p += 3;
  209.  
  210.     Skip(&p);
  211.     if (!ParseNum(&p, 2, 4, &dt.year)) return 0;
  212.     if (dt.year < 21) {
  213.         dt.year += 2000;
  214.     } else if (dt.year < 100) {
  215.         dt.year += 1900;
  216.     }
  217.     
  218.     /* Time. */
  219.  
  220.     Skip(&p);
  221.     if (!ParseNum(&p, 1, 2, &dt.hour)) return 0;
  222.     
  223.     Skip(&p);
  224.     if (*p != ':') return 0;
  225.     p++;
  226.     Skip(&p);
  227.     if (!ParseNum(&p, 2, 2, &dt.minute)) return 0;
  228.     
  229.     Skip(&p);
  230.     if (*p == ':') {
  231.         p++;
  232.         Skip(&p);
  233.         if (!ParseNum(&p, 2, 2, &dt.second)) return 0;
  234.     }
  235.     
  236.     /* Zone. */
  237.     
  238.     Skip(&p);
  239.     if (isalpha(*p)) {
  240.         if (MyStrNEqual(p, "GMT", 3)) {
  241.             tzDelta = 0;
  242.             p += 3;
  243.         } else if (MyStrNEqual(p, "UT", 2)) {
  244.             tzDelta = 0;
  245.             p += 2;
  246.         } else if (MyStrNEqual(p, "EST", 3)) {
  247.             sign = -1;
  248.             tzDelta = 500;
  249.             p += 3;
  250.         } else if (MyStrNEqual(p, "EDT", 3)) {
  251.             sign = -1;
  252.             tzDelta = 400;
  253.             p += 3;
  254.         } else if (MyStrNEqual(p, "CST", 3)) {
  255.             sign = -1;
  256.             tzDelta = 600;
  257.             p += 3;
  258.         } else if (MyStrNEqual(p, "CDT", 3)) {
  259.             sign = -1;
  260.             tzDelta = 500;
  261.             p += 3;
  262.         } else if (MyStrNEqual(p, "MST", 3)) {
  263.             sign = -1;
  264.             tzDelta = 700;
  265.             p += 3;
  266.         } else if (MyStrNEqual(p, "MDT", 3)) {
  267.             sign = -1;
  268.             tzDelta = 600;
  269.             p += 3;
  270.         } else if (MyStrNEqual(p, "PST", 3)) {
  271.             sign = -1;
  272.             tzDelta = 800;
  273.             p += 3;
  274.         } else if (MyStrNEqual(p, "PDT", 3)) {
  275.             sign = -1;
  276.             tzDelta = 700;
  277.             p += 3;
  278.         } else {
  279.             return 0;
  280.         }
  281.     } else if (*p == '+' || *p == '-') {
  282.         sign = *p == '+' ? +1 : -1;
  283.         p++;
  284.         Skip(&p);
  285.         if (!ParseNum(&p, 4, 4, &tzDelta)) return 0;
  286.     } else {
  287.         return 0;
  288.     }
  289.     
  290.     Skip(&p);
  291.     if (*p != 0) return 0;
  292.  
  293.     /* Convert to seconds since 1/1/1904 */
  294.     
  295.     DateToSeconds(&dt, &result);
  296.     result -= sign * (3600*((long)tzDelta/100) + 60*((long)tzDelta%100));
  297.     return result;
  298. }
  299.  
  300.  
  301. /*----------------------------------------------------------------------------
  302.     Cleanup822Date
  303.     
  304.     Converts an RFC822 date/time string into a Mac-style date/time string
  305.     in local time.
  306.     
  307.     Entry:    date = RFC822 date/time string.
  308.             
  309.     Exit:    date = Mac-style date/time string.
  310.     
  311.     If the string cannot be parsed or converted, or if the Map control
  312.     panel is not installed, the string is unchanged.
  313. ----------------------------------------------------------------------------*/
  314.  
  315. void Cleanup822Date (char *date)
  316. {
  317.     MachineLocation    loc;
  318.     long gmtOffset;
  319.     unsigned long secs;
  320.     Str255 time;
  321.  
  322.     /* Get our location. Return if Map control panel not installed. */
  323.     
  324.     ReadLocation(&loc);
  325.     if (loc.latitude == 0 && loc.longitude == 0 && loc.gmtFlags.gmtDelta == 0) return;
  326.  
  327.     /* Get our offset in seconds from GMT. */
  328.     
  329.     gmtOffset = loc.gmtFlags.gmtDelta & 0x00FFFFFF;
  330.     if ((gmtOffset & 0x00800000) != 0) gmtOffset |= 0xFF000000;
  331.  
  332.     /* Try to parse the date we were passed. */
  333.     
  334.     secs = Parse822Date(date);
  335.     if (secs == 0) return;
  336.  
  337.     /* Correct for our timezone. */
  338.     
  339.     secs += gmtOffset;
  340.  
  341.     /* Convert it back into a Mac-style date/time string. */
  342.     
  343.     IUDateString(secs, abbrevDate, (StringPtr)date);
  344.     p2cstr((StringPtr)date);
  345.     strcat(date, " ");
  346.     IUTimeString(secs, true, time);
  347.     strcat(date, p2cstr(time));
  348. }
  349.